/*
 * PDMParser.java
 */
package mango.orm.entity.maker;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import mango.functions.FuncString;
import mango.orm.OrmTypes;
import mango.orm.TypesException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;



/**
 * 解析PDM 将其转化为Table
 * 
 * @author zhangms
 */
public final class PDMParser {
    
    /**
     * 将PDM文件解析为一个Table序列
     * 
     * @param pdmfile
     * @param tableName 
     * @return
     * @throws DocumentException
     */
    public static List<EOTable> parse(String pdmfile) throws DocumentException {
        List<EOTable> ret = new ArrayList<EOTable>();

        Element root = PDMParser.getRoot(pdmfile);
        Element tables = PDMParser.getTables(root);
        Iterator<?> iter = tables.elementIterator();
        while (iter.hasNext()) {
            Element table = (Element) iter.next();
            if ("table".equalsIgnoreCase(table.getName())) {
                ret.add(PDMParser.toTable(table));
            }
        }
        return ret;
    }
    
    public static List<EOTable> parse(String pdmfile, String tableCode) throws DocumentException {
        List<EOTable> ret = new ArrayList<EOTable>();

        Element root = PDMParser.getRoot(pdmfile);
        Element tables = PDMParser.getTables(root);
        Iterator<?> iter = tables.elementIterator();
        while (iter.hasNext()) {
            Element table = (Element) iter.next();
            if ("table".equalsIgnoreCase(table.getName())) {
                Element code = table.element("Code");
                if (code != null) {
                    if (tableCode.equalsIgnoreCase(code.getTextTrim())) {
                        ret.add(PDMParser.toTable(table));
                        break;
                    }
                }
            }
        }
        return ret;
    }

    private static EOTable toTable(Element tableElement) {
        EOTable table = new EOTable();
        String id = tableElement.attribute("Id").getValue();
        table.setId(id);
        Element name = tableElement.element("Name");
        if (name != null) {
            table.setName(name.getTextTrim());
        }
        Element code = tableElement.element("Code");
        if (code != null) {
            table.setCode(FuncString.firstUpper(code.getTextTrim()));
        }
        Element comment = tableElement.element("Comment");
        if (comment != null) {
            table.setComment(comment.getTextTrim());
        }
        Element columns = tableElement.element("Columns");
        if (columns != null) {
            try {
                table.setColumns(PDMParser.toColumns(columns));
            }
            catch(TypesException e) {
                throw new TypesException(name.getTextTrim() + " " + code.getTextTrim() + ";" + e.getMessage());
            }
        }
        Element keys = tableElement.element("Keys");
        if (keys != null) {
            table.setKeys(PDMParser.toKeys(keys));
        }
        Element primaryKey = tableElement.element("PrimaryKey");
        if (primaryKey != null) {
            table.setPrimaryKey(PDMParser.primaryKeyId(primaryKey));
        }
        return table;
    }

    private static String primaryKeyId(Element primaryKey) {
        String ret = primaryKey.element("Key").attributeValue("Ref");
        return ret;
    }

    private static List<EOKey> toKeys(Element keys) {
        List<EOKey> ret = new ArrayList<EOKey>();
        Iterator<?> iter = keys.elementIterator();
        while (iter.hasNext()) {
            EOKey key = new EOKey();
            Element keyElement = (Element) iter.next();
            String id = keyElement.attributeValue("Id");
            key.setId(id);
            Element name = keyElement.element("Name");
            if (name != null) {
                key.setName(name.getTextTrim());
            }
            Element code = keyElement.element("Code");
            if (code != null) {
                key.setCode(code.getTextTrim());
            }
            Element keycols = keyElement.element("Key.Columns");
            if (keycols != null) {
                Iterator<?> i = keycols.elementIterator();
                while (i.hasNext()) {
                    Element keycol = (Element) i.next();
                    key.addColumn(keycol.attributeValue("Ref"));
                }
                ret.add(key);
            }
        }
        return ret;
    }

    private static List<EOColumn> toColumns(Element columns) {
        List<EOColumn> ret = new ArrayList<EOColumn>();
        Iterator<?> iter = columns.elementIterator();
        while (iter.hasNext()) {
            EOColumn column = new EOColumn();
            Element col = (Element) iter.next();
            String id = col.attribute("Id").getValue();
            column.setId(id);

            Element name = col.element("Name");
            if (name != null) {
                column.setName(name.getTextTrim());
            }
            Element code = col.element("Code");
            if (code != null) {
                column.setCode(code.getTextTrim());
            }
            Element comment = col.element("Comment");
            if (comment != null) {
                column.setComment(comment.getTextTrim());
            }
            Element length = col.element("Length");
            if (length != null) {
                column.setLength(length.getTextTrim());
            }
            Element precision = col.element("Precision");
            if (precision != null) {
                column.setPrecision(precision.getTextTrim());
            }
            Element dataType = col.element("DataType");
            if (dataType != null) {
                String dt = dataType.getTextTrim();
                try {
                    column.setJdbcType(OrmTypes.func1(dt, column.getLength(), column.getPrecision()));
                    column.setJavaType(OrmTypes.func2(dt, column.getLength(), column.getPrecision()));
                }
                catch(TypesException e) {
                    throw new TypesException(name.getTextTrim() + " " + code.getTextTrim() + " " +  e.getMessage());
                }
            }
            ret.add(column);
        }
        return ret;
    }

    private static Element getRoot(String pdmfile) throws DocumentException {
        SAXReader reader = new SAXReader();
        Document doc = reader.read(new File(pdmfile));
        Element root = doc.getRootElement();
        return root;
    }

    private static Element getTables(Element root) {
        Element ret = null;
        Iterator<?> iter = root.elementIterator();
        while (iter.hasNext()) {
            Element e = (Element) iter.next();
            if ("tables".equalsIgnoreCase(e.getName())) {
                ret = e;
                break;
            }
            else {
                ret = PDMParser.getTables(e);
            }
        }
        return ret;
    }
}
